﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.IO;
using System.IO.Ports;
using System.Linq;
using System.Runtime.InteropServices;
using System.Security.Principal;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using ControlExs;
using ControlExtensions;
using Microsoft.Win32;


namespace WSNs
{
    public partial class Form1 : FormEx
    {
        public delegate void UpdataDirEventHandler(int nodeID, string dir); //更新文件目录事件
        public delegate void SendFileNameEventHandler(); //更新文件目录事件
        public delegate void FusionIsOkEventHandler(int nodeID, int flag); //融合完成回复信息

        private NodesData _nodesData = NodesData.GetInstance();
        // private AcqConfig _acqConfig = AcqConfig.GetInstance();
        private DataListener _dataListener = new DataListener();
        private AsciitoString _ascToString = new AsciitoString();
        private SampleManagement _formSample;
        private CtlNetworkConfig _ctlNetConfig = new CtlNetworkConfig();
        private CtlAcqConfig _ctlAcqConfig = new CtlAcqConfig();
        public CtlNodeInfo _ctlNodeInfo = new CtlNodeInfo();
        private StructBytes _structBytes = new StructBytes(); //结构体与数据转换

        private UpdataDirEventHandler _updataDir;
        private SendFileNameEventHandler _sendFileName;

        private Point _mouseDownPoint = new Point(0, 0);
       // private Dictionary<int, bool> _nodeIsLive = new Dictionary<int, bool>(); //定时器每隔6秒检查一次节点是否在线
        public Dictionary<int, bool> _fusionDataIsSaved = new Dictionary<int, bool>(); //标志融合数据是否已保存

        private string _nodeNamePre = "Node:";                          //左侧CheckList中节点名称显示前缀
        private DataType _dataType;                                     //传递的数据类型
        private ChannelType _channelType = ChannelType.SingleChannel;   //节点通道类型
        private bool _isLive;                                           //是否实时显示
        private ShowType _showTyte = ShowType.OnlyData;                 //是否显示FFT


        private static int _maxRouterNum;  //记录设置的最大路有数
        private int _showFusionIndex = 1; //记录数据融合显示位置
        private int _sendDataCount = 0; //记录发送的数据包数
        System.Timers.Timer myTimer;  //用于启动采集
        System.Timers.Timer mystopcollectionTimer;  //用于失能停止采集按钮
        public bool isfreeacq = false; //是否为自由采样
        internal DataListener GetDataLister()
        {
            return _dataListener;
        }
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {

            #region 添加侧边栏panel

            //网络信息配置
            _ctlNetConfig.ConfigEvent += CtlNetworkConfig_ConfigEvent;
            _ctlNetConfig.DisConnectEvent += CtlNetworkConfig_DisConnectEvent;
            _ctlNetConfig.Anchor = AnchorStyles.Left | AnchorStyles.Bottom | AnchorStyles.Top;
            _ctlNetConfig.Height = panel2.Height - 4;
            _ctlNetConfig.Location = new Point(panel2.Location.X + toolStrip1.Width + 2,panel2.Location.Y);
            _ctlNetConfig.Visible = false;
            _ctlNetConfig.BringToFront();
            this.Controls.Add(_ctlNetConfig);

            //节点采集配置
            _ctlAcqConfig.AcqConfigEvent += CtlAcqConfig_AcqConfigEvent;
            _ctlAcqConfig.Anchor = AnchorStyles.Left | AnchorStyles.Bottom | AnchorStyles.Top;
            _ctlAcqConfig.Height = panel2.Height - 4;
            _ctlAcqConfig.Location = new Point(panel2.Location.X + toolStrip1.Width + 2, panel2.Location.Y);
            _ctlAcqConfig.Visible = false;
            _ctlAcqConfig.BringToFront();
            this.Controls.Add(_ctlAcqConfig);

            //节点信息配置
            _ctlNodeInfo.DeleteNodeEvent += CtlNodeInfo_DeleteNodeEvent;
            _ctlNodeInfo.clb_nodesshow.ItemCheck +=clb_nodesshow_ItemCheck;
            _ctlNodeInfo.Anchor = AnchorStyles.Left | AnchorStyles.Bottom | AnchorStyles.Top;
            _ctlNodeInfo.Height = panel2.Height;
            _ctlNodeInfo.Location = new Point(panel2.Location.X + toolStrip1.Width + 2, panel2.Location.Y);
            _ctlNodeInfo.Visible = false;
            _ctlNodeInfo.BringToFront();
            this.Controls.Add(_ctlNodeInfo);

            #endregion

            //BackColor = Color.FromArgb(210, 210, 210);
          // _dataType = DataType.Unsigned16;
            _dataType = DataType.Signed24;
            //生成数据接收事件
            _dataListener.Init();
            _dataListener.ReceivedDataEvent += DataListener_ReceivedDataEvent; //接收到数据包
            _dataListener.AddrReceivedEvent += DataListener_AddrReceivedEvent; //接收地址关系包事件
            _dataListener.LinkDectReceivedEvent += DataListener_LinkDectReceivedEvent;//接收到链路质量检测包
            //_dataListener.RouterStartTimeEvent += DataListener_RouterStartTimeEvent;//发送退避时间包
            _dataListener.DataBackAcq += DataListener_DataBackAcqEvent;
            _dataListener.TestEvent += DataListener_TestEvent;
            nodesTopology1.AcqStructChangeEvent += NodesTopology_AcqStructChangeEvent; //采集参数从新配置触发事件
            _ctlAcqConfig.AcqTimeConfigEvent += CtlAcqConfig_AcqTimeConfigEvent;   //用于失能启动、停止采集事件

            menuStrip_menu.ForeColor = Color.Black;
            //启动是居中
            Location = new Point(Screen.PrimaryScreen.WorkingArea.Width / 2 - Width / 2,
                Screen.PrimaryScreen.WorkingArea.Height / 2 - Height / 2);

            _formSample = new SampleManagement(this);
            _updataDir = _formSample.UpdataDir;
            _sendFileName = _formSample.SendFileName;

            tabControl1.SelectedIndex = 1;

            string command = Environment.CommandLine;//获取进程命令行参数
            string[] para = command.Split('\"');
            if (para.Length > 3)  // 有文件打开时 para长度为5，第三个为要打开的文名
            {
                string pathC = para[3];//获取打开的文件的路径
                if (pathC.Length > 2)
                {
                    OpenData(pathC);
                }
            }
            tabControl1.SelectedIndex = 0;
            nodesTopology1.BackColor = Color.White; //拓扑背景图为白色 

            myTimer = new System.Timers.Timer(12000);//定时周期12秒
            myTimer.Elapsed += myTimer_Collection_Elapsed;//到12秒了做的事件
            myTimer.AutoReset = false; //是否不断重复定时器操作
            myTimer.Enabled = false;

            tsb_start.Enabled = false; //失能启动采集
            tsb_stop.Enabled = false;
        }

        void myTimer_Collection_Elapsed(object sender, System.Timers.ElapsedEventArgs e) //定时器处理事件
        {
            tsb_start.Enabled = true; //使能启动采集
            tsb_stop.Enabled = false;
        }
        private void CtlAcqConfig_AcqTimeConfigEvent(double acq_stoptime,bool isFreeAcq)  //失能启动、停止采集按钮
        {
            if (isFreeAcq == false)
            {
                isfreeacq = false;
                double tmp_time = acq_stoptime * 1000 / 3;
                int my_stoptime = (int)tmp_time;
                mystopcollectionTimer = new System.Timers.Timer(my_stoptime);//定时周期为采样长度除以采样频率
                mystopcollectionTimer.Elapsed += mystopcollectionTimer_Collection_Elapsed;
                mystopcollectionTimer.AutoReset = false; //是否不断重复定时器操作
                mystopcollectionTimer.Enabled = false;
            }
            else
            {
                isfreeacq = true;
            }
        }

        void mystopcollectionTimer_Collection_Elapsed(object sender, System.Timers.ElapsedEventArgs e) //定时器处理事件
        {
            tsb_start.Enabled = false; //失能启动采集
            tsb_stop.Enabled = false;
            MessageBox.Show("定长采样完成!");
        }
        private void ColorSet(int c)
        {
            switch (c)
            {
                case 0:
                    menuStrip_menu.ForeColor = Color.Black;
                    TextForeColor = Color.Black;
                    toolStrip2.ForeColor = Color.Black;
                    toolStrip2.BackColor = Color.FromArgb(214, 219, 233);
                    BackColor = Color.FromArgb(214, 219, 233);
                    break;
                case 1:
                    menuStrip_menu.ForeColor = Color.White;
                    TextForeColor = Color.White;
                    toolStrip2.ForeColor = Color.White;
                    toolStrip2.BackColor = Color.FromArgb(64, 64, 64);
                    BackColor = Color.FromArgb(64, 64, 64);
                    break;
            }
            
        }

        private bool CtlNetworkConfig_ConfigEvent(NetworkConfigStructure net)
        {
            _dataListener.SetSerialPort(net.SPort, net.SerialRate);
            if (!SendSerialPack(_ctlNetConfig.NetworkBuildToList())) return false;
            nodesTopology1.DelayListInit(net.MaxRouter); //更新最大路由数，用于计算路由退避时间
            _maxRouterNum = net.MaxRouter;
            toolStrip_btn_config.BackColor = Color.Transparent;
            _ctlNetConfig.Visible = false;
            return true;
        }

        private void CtlNetworkConfig_DisConnectEvent(NetworkConfigStructure sp)
        {
            _dataListener.CloseSerialPort();
        }

        private void CtlAcqConfig_AcqConfigEvent(AcqStructure acq, ChannelType chn)
        {
            _channelType = chn;                     //通道类型
            SendAcqStruct(acq);
            nodesTopology1.UpdataAllAcq(acq);
            _nodesData.SetNodeAcq(acq);                                          //更新节点采集参数
            if (_channelType != chn)
            {
                RebuidNodeChannel();
            }
            toolStrip_btn_acqset.BackColor = Color.Transparent;
            _ctlAcqConfig.Visible = false;

            tsb_start.Enabled = false; //失能启动采集
            tsb_stop.Enabled = false;
            myTimer.Enabled = true; //采集配置后，用于使能启动采集
            Control.CheckForIllegalCrossThreadCalls = false;
        }

        private void CtlNodeInfo_DeleteNodeEvent(int id)
        {
            //panel_data.Controls.Clear();
            CtlDataDrawer cdTemp = _nodesData.GetDataDrawer(id);
            CtlDataFft fftTemp = _nodesData.GetFFTDrawer(id);
            panel_data.Controls.Remove(cdTemp);
            panel_data.Controls.Remove(fftTemp);
            _nodesData.RemoveSelectedNode(id);
            //_nodeIsLive.Remove(id);
            nodesTopology1.RemoveSelectedNodeTopo(id);
            nodesTopology1.Invalidate();
            UpdataPanelData();
        }
        private void NodesTopology_AcqStructChangeEvent(AcqStructure acq,double sensitivity)
        {
            _nodesData.SetSensitivity(acq.NodeID, sensitivity);
            //SendAcqStruct(acq);
        }

        /// <summary>
        /// 接收到地址关系包
        /// </summary>
        /// <param name="node"></param>
        private void DataListener_AddrReceivedEvent(CtlNode node)
        {
            this.UIThreadBeginInvoke(delegate
            {
                if (nodesTopology1.AddnodeTopo(node)) //
                {
                    switch (node.NodeType)
                    {
                        case NodesType.Router:
                            SendSerialPack(nodesTopology1.GetRouterDelayTimeList(node.NodeID, node.FatherNode));
                            break;
                        case NodesType.EndNode:
                            _nodesData.AddNode(node);
                            break;
                    }
                    UpdataPanelData();
                    UpdataCtlNodeInfo();
                }
                
                nodesTopology1.UpdateTopo();

            });

        }

        /// <summary>
        /// 接收到链路质量检测包事件
        /// </summary>
        /// <param name="nodeID">节点号</param>
        /// <param name="dataPak">信号强度</param>
        public void DataListener_LinkDectReceivedEvent(int nodeId, int[,] Link,int count)
        {   
            int sValue=0;
           // int count = _nodesData.GetShowNodes().ToArray().Length;
            this.UIThreadBeginInvoke(delegate
            {
                for (int k = 0; k < count; k++)
                {
                    if (Link[k, 0] == nodeId)
                    {
                        if (Link[k, 1] == 0)
                        {
                          sValue = 0;                                
                        }
                        if ( Link[k, 1] > 0 && Link[k, 1] <= 16)
                          sValue = 1;
                        if ( Link[k, 1] > 16 && Link[k, 1] <= 32)
                          sValue = 2;
                        if ( Link[k, 1] > 32 && Link[k, 1] <= 64)
                          sValue = 3;
                        if ( Link[k, 1] > 64 && Link[k, 1] <= 128)
                          sValue = 4;
                        if ( Link[k, 1] > 128 && Link[k, 1] <= 192)
                          sValue = 5;
                        if ( Link[k, 1] > 192 && Link[k, 1] < 255)
                          sValue = 6;
                        if (!nodesTopology1._LQIValue.ContainsKey(nodeId))
                        {
                            nodesTopology1._LQIValue.Add(nodeId, Link[k, 1]);
                        }
                        else
                        {
                            nodesTopology1._LQIValue[nodeId] = Link[k, 1];
                        }
                        _nodesData.AddSignal(nodeId, sValue);
                    
                    }

                }
                UpdataPanelData();
                UpdataCtlNodeInfo();
                nodesTopology1.UpdateTopo();
            });

        }
        /// <summary>
        /// 接收到数据包事件
        /// </summary>
        /// <param name="nodeID">节点号</param>
        /// <param name="dataPak">数据</param>
        private void DataListener_ReceivedDataEvent(int nodeID, List<byte> dataPak)
        {
            if (_nodesData.ContainsNode(nodeID))
                _nodesData.AddData(nodeID, dataPak, _isLive, _dataType);
        }

        private void DataListener_DataBackAcqEvent(AcqStructure acq)
        {
            nodesTopology1.UpdataNodeAcq(acq.NodeID, acq);
            _nodesData.SetNodeAcq(acq);
            _nodesData.UpdataTitle(acq.Frequency, acq.NodeID);
            _nodesData.SetMeasuerRange(acq.NodeID, acq.MeasuerRange); //更新放大倍数
        }

        private void DataListener_TestEvent(List<byte> data,DataStutas stu)
        {
            this.UIThreadBeginInvoke(() =>
            {
                string s = null;
                switch (stu)
                {
                    case DataStutas.Ok:
                        label_dataStatus.Text = "状态：重复数据包：";
                        break;
                    case DataStutas.StartErr:
                        label_dataStatus.Text = "状态：数据起始错误";
                        for (int i = 0; i < data.Count; i++)
                            s += data[i]+"\t";
                        //MessageBox.Show("数据起始错误:\r\n" + s);  //huangyi
                        break;
                    case DataStutas.EndErr:
                        label_dataStatus.Text = "状态：数据尾错误";
                        for (int i = 0; i < data.Count; i++)
                            s += data[i]+"\t";
                        //MessageBox.Show("数据尾错误:\r\n" + s);  //huangyi
                        break;
                    case DataStutas.SerialTypeErr:
                        label_dataStatus.Text = "状态：串口包类型错误";
                        s = data.Aggregate(s, (current, t) => current + (t + "\t"));
                        MessageBox.Show("串口包类型错误:\r\n" + s);
                        break;
                    case DataStutas.DataPackRev:
                        label_dataStatus.Text = "状态：接收到数据包";
                        break;
                    case DataStutas.AddrPackRev:
                        label_dataStatus.Text = "状态：接收到地址关系包";
                        break;
                    case DataStutas.PackSerialResErr:
                        //MessageBox.Show("包序号不连续");  //huangyi
                        break;
                    case DataStutas.LinkDectPackRec:
                        label_dataStatus.Text = "状态：链路质量包";
                        break;
                    /*case DataStutas.NodeState: ///huangyi
                             //label_dataStatus.Text = "状态：采集完毕";
                             //MessageBox.Show("采集完毕");
                             break;*/
                }
            });
        }

        private void SendAcqStruct(AcqStructure acq)
        {            
            List<byte> lb = new List<byte> { };
            lb.AddRange(_structBytes.StructToBytes(acq, Marshal.SizeOf(acq)));
            lb.Insert(0, (byte)CmdType.AcqCmd); //添加命令类型标识
            lb.Insert(0, (byte)SerialPackType.CmdPack);  //添加包类型标识
            lb.Add((byte) nodesTopology1.GetNextNodeOfGetway(acq.NodeID)); // 网关到本节点的下一跳地址，网络参数传递时用
            SendSerialPack(lb);
          
            _nodesData.UpdataTitle(acq.Frequency, acq.NodeID);
            _nodesData.SetMeasuerRange(acq.NodeID, acq.MeasuerRange); //更新放大倍数
        }

        /// <summary>
        /// 通道数改变，从建节点显示
        /// </summary>
        private void RebuidNodeChannel()
        {
            RemoveAllNodes();
        }

        #region Updata

        private void UpdataPanelData()
        {
            int height, width, eachHeight, eachWidth, count;
            Control[] ctlDrawer;
            List<int> listNodesToShow;
            bool isDouble;
            switch (_showTyte)
            {
                case ShowType.OnlyFft:
                    panel_data.SuspendLayout();
                    listNodesToShow = _nodesData.GetShowNodes();
                    count = listNodesToShow.Count;
                    isDouble = false;
                    panel_data.VerticalScroll.Value = 0;
                    if (count < 1)
                    {
                        panel_data.ResumeLayout();
                        return;
                    }
                    listNodesToShow.Sort();
                    //最多只显示8个
                    if (count > 8) count = 8;
                    if (count > 4)
                    {
                        isDouble = true;
                        count = (int) (count/2.0f + 0.5);
                    }
                    height = panel_data.Height;
                    width = panel_data.Width;
                    if (listNodesToShow.Count > 8) width = width - 20;
                    eachHeight = height/count;
                    eachWidth = width;
                    if (isDouble) eachWidth = width/2;
                    count = listNodesToShow.Count;
                    ctlDrawer = new Control[count];
                    for (int i = 0; i < count; i++)
                    {
                        CtlDataFft ctlDataDrawer = _nodesData.GetFFTDrawer(listNodesToShow[i]);
                        ctlDataDrawer.Width = eachWidth;
                        ctlDataDrawer.Height = eachHeight;
                        ctlDataDrawer.Location = isDouble
                            ? new Point(i%2*eachWidth, i/2*eachHeight)
                            : new Point(0, i*eachHeight);
                        ctlDrawer[i] = ctlDataDrawer;
                    }
                    this.UIThreadBeginInvoke(delegate
                    {
                        panel_data.Controls.AddRange(ctlDrawer);
                        panel_data.ResumeLayout();
                    });
                    break;
                case ShowType.DataAndFft:
                    panel_data.SuspendLayout();
                    listNodesToShow = _nodesData.GetShowNodes();
                    count = listNodesToShow.Count;
                    panel_data.VerticalScroll.Value = 0;
                    if (count < 1)
                    {
                        panel_data.ResumeLayout();
                        return;
                    }
                    listNodesToShow.Sort();
                    eachWidth = panel_data.Width/2;
                    if (count > 4) //最多只显示4个
                    {
                        count = 4;
                        eachWidth = (panel_data.Width - 20)/2;
                    }
                    eachHeight = panel_data.Height/count;
                    count = listNodesToShow.Count;
                    ctlDrawer = new Control[count*2];
                    for (int i = 0; i < count; i++)
                    {
                        CtlDataDrawer ctlDataDrawer = _nodesData.GetDataDrawer(listNodesToShow[i]);
                        ctlDataDrawer.Width = eachWidth;
                        ctlDataDrawer.Height = eachHeight;
                        ctlDataDrawer.Location = new Point(0, i*eachHeight);
                        ctlDrawer[2*i] = ctlDataDrawer;
                        CtlDataFft ctlFft = _nodesData.GetFFTDrawer(listNodesToShow[i]);
                        ctlFft.Width = eachWidth;
                        ctlFft.Height = eachHeight;
                        ctlFft.Location = new Point(eachWidth, i*eachHeight);
                        ctlDrawer[2*i + 1] = ctlFft;
                    }
                    this.UIThreadBeginInvoke(delegate
                    {
                        panel_data.Controls.AddRange(ctlDrawer);
                        panel_data.ResumeLayout();
                    });
                    break;
                default:
                    panel_data.SuspendLayout();
                    listNodesToShow = _nodesData.GetShowNodes();
                    count = listNodesToShow.Count;
                    isDouble = false;
                    panel_data.VerticalScroll.Value = 0;
                    if (count < 1)
                    {
                        panel_data.ResumeLayout();
                        return;
                    }
                    listNodesToShow.Sort();
                    //最多只显示8个
                    if (count > 8) count = 8;
                    if (count > 4)
                    {
                        isDouble = true;
                        count = (int) (count/2.0f + 0.5);
                    }
                    height = panel_data.Height;
                    width = panel_data.Width;
                    if (listNodesToShow.Count > 8) width = width - 20;
                    eachHeight = height/count;
                    eachWidth = width;
                    if (isDouble) eachWidth = width/2;
                    count = listNodesToShow.Count;
                    this.UIThreadBeginInvoke(delegate //跨线程调用控件
                    {
                        ctlDrawer = new Control[count];
                        for (int i = 0; i < count; i++)
                        {
                            CtlDataDrawer ctlDataDrawer = _nodesData.GetDataDrawer(listNodesToShow[i]);
                            ctlDataDrawer.Width = eachWidth;
                            ctlDataDrawer.Height = eachHeight;
                            ctlDataDrawer.Location = isDouble
                                ? new Point(i%2*eachWidth, i/2*eachHeight)
                                : new Point(0, i*eachHeight);
                            ctlDrawer[i] = ctlDataDrawer;
                        }
                        panel_data.Controls.AddRange(ctlDrawer);
                        panel_data.ResumeLayout();
                    });
                    break;
            }
        }

        private void UpdataCtlNodeInfo()
        {
            List<int> nodes = _nodesData.GetAllnodes();
            nodes.Sort();
            _ctlNodeInfo.clb_nodesshow.Items.Clear();
            foreach (int t in nodes)
            {
                _ctlNodeInfo.clb_nodesshow.Items.Add("Node: " + t, true);
            }
        }

        private void panel_data_SizeChanged(object sender, EventArgs e)
        {
            UpdataPanelData();
        }

        private void clb_nodesshow_ItemCheck(object sender, ItemCheckEventArgs e)
        {
            if (_ctlNodeInfo.clb_nodesshow.SelectedItem == null) return;
            string strNodeId = _ctlNodeInfo.clb_nodesshow.SelectedItem.ToString().Replace(_nodeNamePre, "").Trim();
            int nodeID = int.Parse(strNodeId);
            if (e.NewValue == CheckState.Checked)
            {
                _nodesData.AddShowNode(nodeID);
            }
            else
            {
                _nodesData.RemoveShowNode(nodeID);
            }
            panel_data.Controls.Clear();
            UpdataPanelData();
        }

        #endregion

        #region Move Window

        private void menuStrip_menu_MouseMove(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                Location = new Point(e.X - _mouseDownPoint.X + Location.X, e.Y - _mouseDownPoint.Y + Location.Y);
            }
        }

        private void menuStrip_menu_MouseDown(object sender, MouseEventArgs e)
        {
            _mouseDownPoint = e.Location;
        }

        #endregion

        #region 侧边栏显示操作

        private void toolStrip_btn_config_Click(object sender, EventArgs e)
        {
            _ctlNetConfig.Visible = !_ctlNetConfig.Visible;
            _ctlAcqConfig.Visible = false;
            _ctlNodeInfo.Visible = false;
            toolStrip_btn_config.BackColor = _ctlNetConfig.Visible ? Color.SkyBlue : Color.Transparent;
            _ctlNetConfig.BringToFront();
        }

        private void toolStrip_btn_nodes_ifo_Click(object sender, EventArgs e)
        {
            _ctlNodeInfo.Visible = !_ctlNodeInfo.Visible;
            _ctlAcqConfig.Visible = false;
            _ctlNetConfig.Visible = false;
            toolStrip_btn_nodes_ifo.BackColor = _ctlNodeInfo.Visible ? Color.SkyBlue : Color.Transparent;
            _ctlNodeInfo.BringToFront();
        }

        private void toolStrip_btn_acqset_Click(object sender, EventArgs e)
        {
            _ctlAcqConfig.Visible = !_ctlAcqConfig.Visible;
            _ctlNodeInfo.Visible = false;
            _ctlNetConfig.Visible = false;
            toolStrip_btn_acqset.BackColor = _ctlAcqConfig.Visible ? Color.SkyBlue : Color.Transparent;
            _ctlAcqConfig.BringToFront();
        }

        #endregion

        /// <summary>
        /// 需要从串口发出的数据
        /// </summary>
        /// <param name="lb">第一字节为包的类型 SerialPackType，后面所有的为数据</param>
        /// <returns></returns>
        private bool SendSerialPack(List<byte> lb)
        {
            if (!_dataListener.SerialPortIsOpen()) _dataListener.OpenSerialPort();
            lb.InsertRange(0, BitConverter.GetBytes((UInt16)lb.Count)); //添加数据长度
            lb.InsertRange(0, new byte[] {0xAA, 0x55}); //添加数据头
            lb.AddRange(new byte[] {0x55, 0xAA}); //添加数据尾
            return _dataListener.SendCMD(lb.ToArray());
        }

        //程序退出时关闭串口
        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (!_dataListener.SerialPortIsOpen()) return;
            try
            {
                _dataListener.CloseSerialPort();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString());
            }
        }

        #region 添加节点

        private void MenuItem_AddRoute_Click(object sender, EventArgs e)
        {
            Form_AddNode frmAddNode = new Form_AddNode(NodesType.Router);
            frmAddNode.ConnectAddnode += frmAddNode_connectAddnodeEvent;
            frmAddNode.ShowDialog();
            frmAddNode.Dispose();
        }

        private void MenuItem_AddDevice_Click(object sender, EventArgs e)
        {
            Form_AddNode frmAddNode = new Form_AddNode(NodesType.EndNode);
            frmAddNode.ConnectAddnode += frmAddNode_connectAddnodeEvent;
            frmAddNode.ShowDialog();
            frmAddNode.Dispose();
        }

        private void frmAddNode_connectAddnodeEvent(CtlNode node)
        {
            DataListener_AddrReceivedEvent(node);
        }

        #endregion

        //节点掉线检测
        private void timer_signal_Tick(object sender, EventArgs e)
        {
  /*          List<int> ID = new List<int>();
           // if (_nodesData._nodeIsLive.Keys.Count == 0) return;
            if (_nodesData.GetShowNodes().Count == 0) return;
                ID.AddRange(_nodesData.GetShowNodes());
            //ID.AddRange(_nodesData._nodeIsLive.Keys);
            foreach (int i in ID)
            {
                if (!_nodesData._nodeIsLive[i]) //两次都不在线   //发送掉线命令
                {
                    _nodesData._nodeIsLive.Remove(i);

                    CtlDataDrawer cdTemp = _nodesData.GetDataDrawer(i);
                    CtlDataFft fftTemp = _nodesData.GetFFTDrawer(i);
                    panel_data.Controls.Remove(cdTemp);
                    panel_data.Controls.Remove(fftTemp);
                    _nodesData.RemoveSelectedNode(i);
                    //_nodesData._nodeIsLive.Remove(i);
                    nodesTopology1.RemoveSelectedNodeTopo(i);
                    nodesTopology1._LQIValue.Remove(i);
                    nodesTopology1.Invalidate();
                    UpdataPanelData();
                    nodesTopology1.UpdateTopo();
                    //List<byte> lb = new List<byte> { 0XCB, (byte)i, 0XEC, 0X09, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00 };
                    //DataListener_ReceivedDataEvent(lb); //todo:待添加

                }
                _nodesData._nodeIsLive[i] = false;
            }*/
        }

        private void RemoveAllNodes()
        {
            //todo:还未移除所有添加的元素
            //clb_nodesshow.Items.Clear();
            panel_data.Controls.Clear();
            _nodesData.RemoveAllNode();
            _ctlNodeInfo.RemoveAllItems();
            //_nodeIsLive.Clear();
            _nodesData._nodeIsLive.Clear();
            nodesTopology1.RemoveAllNodesTopo();
            nodesTopology1.Invalidate();
        }

        private void OpenData(string path)
        {
            _isLive = false;
            List<byte> listDataPak = new List<byte>();
            FileStream fs_data = new FileStream(path, FileMode.Open);
            FileInfo fi = new FileInfo(path);
            String str = fi.Extension;
            if (str == ".set")                                                      //打开.set文件
            {
                int chlCount;                                                       //通道数
                int pointCount;                                                     //点数
                _dataType = DataType.DaqData;
                List<byte> listTemp;                                                //缓存列表
                for (int i = 0; i < 64; i++)                                        //读取64字节数据
                {
                    listDataPak.Add((byte)fs_data.ReadByte());
                }
                fs_data.Close();                                                    //关闭文件
                chlCount = System.BitConverter.ToInt32(listDataPak.ToArray(), 0);   //获取通道数
                float freq = System.BitConverter.ToSingle(listDataPak.ToArray(), 16);   //获取采样频率               
                pointCount = System.BitConverter.ToInt32(listDataPak.ToArray(), 20);    //获取点数
                listDataPak.Clear();                                                    //删除所有的数据

                path = path.Replace(".set", ".dat");                                    //将文件扩展名设置为.dat
                fs_data = new FileStream(path, FileMode.Open);                          //打开文件
                byte[] databyte = new byte[pointCount * 4 * chlCount];                  //设置缓存
                fs_data.Read(databyte, 0, pointCount * 4 * chlCount);                   //读取数据
                fs_data.Close();                                                        //关闭文件
                listTemp = databyte.ToList();                                           //转化为列表

                RemoveAllNodes();                                                       //删除所有的节点
                byte nodecount = (byte)_nodesData.GetAllFloatData().Keys.Count;         //打开数据时全部新建节点
                for (byte i = 1; i <= chlCount; i++)                                    //设置通道的数据
                {
                    listDataPak.AddRange(listTemp.GetRange(0, pointCount * 4));         //读取数据到数据包
                    listTemp.RemoveRange(0, pointCount * 4);                            //从缓存中移除数据
                    
                    AcqStructure acq = new AcqStructure();                              //采集参数
                    acq.NodeID = (byte)(i + nodecount);                                 //设置节点编号
                    acq.Frequency = freq;                                               //设置采样频率
                    CtlNode node = new CtlNode
                    {
                        NodeID = acq.NodeID,                                            //节点编号
                        NodeType = NodesType.EndNode,                                   //节点类型
                        AcqStructure = acq                                              //节点采集参数
                    };
                    DataListener_AddrReceivedEvent(node);                                //添加节点
                    DataListener_ReceivedDataEvent(node.NodeID, listDataPak);            //添加数据
                    nodesTopology1.UpdataAllAcq(acq);                                    //更新拓扑结构
                    _nodesData.SetNodeAcq(acq);                                          //更新节点采集参数
                    listDataPak.Clear();                                                 //删除数据
                }                
                return;
            }
            byte[] bytedata = new byte[fs_data.Length];
            fs_data.Read(bytedata, 0, (int)fs_data.Length);
            listDataPak.AddRange(bytedata);
            fs_data.Close();
            AcqStructure acqStruct = (AcqStructure)_structBytes.ByteToStruct(
                listDataPak.GetRange(0, 16).ToArray(), typeof(AcqStructure));
            listDataPak.RemoveRange(0, 16);
            RemoveAllNodes();
            if (acqStruct.NodeID == 0)
                acqStruct.NodeID = 1;
            switch (acqStruct.StorageLocation)
            {
                case StorageLocation.MicroSD:
                    CtlNode node = new CtlNode
                    {
                        NodeID = acqStruct.NodeID,
                        NodeType = NodesType.EndNode,
                        AcqStructure = acqStruct
                    };
                    //_dataType = DataType.Unsigned16;
                    _nodesData.SetMeasuerRange(acqStruct.NodeID, acqStruct.MeasuerRange);
                    DataListener_AddrReceivedEvent(node); //添加节点
                    DataListener_ReceivedDataEvent(node.NodeID, listDataPak);  //添加数据
                    nodesTopology1.UpdataAllAcq(acqStruct);
                    _nodesData.SetNodeAcq(acqStruct);                                          //更新节点采集参数
                    break;
                case StorageLocation.Flash:
                    break;
                case StorageLocation.Wireless:
                    break;
            }
        }

        #region 工具栏按钮操作
        private void tsb_start_Click(object sender, EventArgs e)
        {
            ////todo:test
            if (!_dataListener.SerialPortIsOpen())
            {
                MessageBox.Show("请先打开串口！", "串口未打开");
                return;
            }
            if (_nodesData.GetShowNodes().Count == 0)
            {
                MessageBox.Show("请选择节点 或 等待组建网络!", "无可采集节点");
                return;
            }
            List<byte> lb = new List<byte>();
            AcqStructure ast = new AcqStructure();
            ast.AcqMode = AcqMode.Start;
            lb.AddRange(_structBytes.StructToBytes(ast, Marshal.SizeOf(ast)));
            lb.Add((byte)0); // 网关到本节点的下一跳地址，网络参数传递时用，为0发送到所有节点
            lb.Insert(0, (byte)CmdType.AcqCmd);
            lb.Insert(0, (byte)SerialPackType.CmdPack);
            SendSerialPack(lb);

            tsb_start.Enabled = false;
            if (!isfreeacq)
            {
                mystopcollectionTimer.Enabled = true;
                Control.CheckForIllegalCrossThreadCalls = false;
            }
            else
            {
                tsb_stop.Enabled = true;  //自由采样停止采集按钮使能
            }       
        }
        private void tsb_openfile_Click(object sender, EventArgs e)
        {
            OpenFileDialog openFile = new OpenFileDialog();
            openFile.RestoreDirectory = true;
            openFile.Filter = "工程文件|*.WSN;*.set|所有文件|*.*";
            if (openFile.ShowDialog() == DialogResult.OK)
            {
                string path = openFile.FileName;
                OpenData(path);
            }
            openFile.Dispose();
        }

        private void tsb_config_Click(object sender, EventArgs e)
        {
            toolStrip_btn_config_Click(sender, e);
        }

        private void tsb_rebuild_Click(object sender, EventArgs e)
        {
            //重组网络
            if (!_dataListener.SerialPortIsOpen())
            {
                MessageBox.Show("串口有错误！");
                return;
            }
            List<byte> lb = new List<byte>();                
            lb.Insert(0, (byte)SerialPackType.ReBuild);  //添加包类型标识,重组网络包   
            SendSerialPack(lb);
            RemoveAllNodes();
            nodesTopology1.DelayListInit(_maxRouterNum); //如果是多跳，需要设置最大路由数  huangyi
        }

        private void tsb_acqset_Click(object sender, EventArgs e)
        {
            toolStrip_btn_acqset_Click(sender, e);
        }

        private void tsb_fft_Click(object sender, EventArgs e)
        {
            switch (_showTyte)
            {
                case ShowType.OnlyData:
                    _showTyte = ShowType.DataAndFft;
                    break;
                case ShowType.DataAndFft:
                    _showTyte = ShowType.OnlyFft;
                    break;
                default:
                    _showTyte = ShowType.OnlyData;
                    break;
            }
            panel_data.Controls.Clear();
            UpdataPanelData();
        }

        private void tsb_savefile_Click(object sender, EventArgs e)
        {
            if (_nodesData.GetAllFloatData().Keys.Count == 0)
            {
                MessageBox.Show("无可用数据！");
                return;
            }
            if (_nodesData.GetAllFloatData().Keys.Any(id => _nodesData.GetAllFloatData()[id].Count == 0))
            {
                MessageBox.Show("部分节点无数据，删除后再保存！");
                return;
            }
            SaveFileDialog saveFileDialog = new SaveFileDialog();
            saveFileDialog.Filter = "工程文件|*.WSN|文本文件|*.txt|.set文件|*.set";
            saveFileDialog.FilterIndex = 3;
            saveFileDialog.RestoreDirectory = true;
            saveFileDialog.FileName = DateTime.Now.ToString().Replace('/', '-').Replace(':', '-').Trim();
            if (saveFileDialog.ShowDialog() != DialogResult.OK) return;
            try
            {
                FileInfo fi = new FileInfo(saveFileDialog.FileName);
                switch (fi.Extension)
                {
                    case ".WSN": //保存原始数据
                        Stream sdata = new FileStream(saveFileDialog.FileName, FileMode.Create);
                        int index = 0;
                        foreach (int i in _nodesData.GetAllFloatData().Keys)
                        {
                            byte[] data = _nodesData.GetAllByteData(i).ToArray(); //todo:获取数据待修改
                            sdata.Write(data, index, data.Length);
                            index += data.Length;
                           
                        }
                        sdata.Flush();
                        sdata.Close();
                        MessageBox.Show("转换完成！");
                        break;
                    case ".txt": //保存为txt
                        StreamWriter sw = new StreamWriter(saveFileDialog.FileName, false);
                        int maxlength = 0;
                        foreach (int id in _nodesData.GetAllFloatData().Keys) //写入文件头
                        {
                            sw.WriteLine("节点" + id + "采集点数：" + _nodesData.GetAllFloatData()[id].Count);
                        }
                        sw.Write("time:");
                        sw.Write("\t");
                        foreach (int id in _nodesData.GetAllFloatData().Keys) //写入文件头
                        {
                            sw.Write("node:" + id);
                            sw.Write("\t");
                            if (maxlength >= _nodesData.GetAllFloatData()[id].Count) continue;
                            maxlength = _nodesData.GetAllFloatData()[id].Count;
                        }
                        sw.Write("\r\n");
                        //获得采样频率
                        float frequency = 1024;
                        foreach (var item in _nodesData.GetAllNodeAcq())
                        {
                            frequency = item.Value.Frequency;
                        }
                        for (int i = 0; i < maxlength; i++)
                        {
                            sw.Write((i / frequency).ToString("f6"));
                            sw.Write("\t");
                            foreach (int id in _nodesData.GetAllFloatData().Keys)
                            {
                                if (i < _nodesData.GetAllFloatData()[id].Count)
                                {
                                    sw.Write(_nodesData.GetAllFloatData()[id][i].ToString("f6"));
                                    sw.Write("\t");
                                }
                                else
                                {
                                    sw.Write("\t");
                                }
                            }
                            sw.Write("\r\n");
                        }
                        sw.Close();
                        MessageBox.Show("转换完成！");
                        break;
                    case ".set": //保存为实验室文件
                        int minlength = 1000000000;
                        int chnCount = _nodesData.GetAllFloatData().Keys.Count;         //通道数
                        foreach (int id in _nodesData.GetAllFloatData().Keys)           //获取所有节点的最短数据长度
                        {
                            if (minlength > _nodesData.GetAllFloatData()[id].Count)
                                minlength = _nodesData.GetAllFloatData()[id].Count;
                        }
                        FileStream fis = new FileStream(saveFileDialog.FileName, FileMode.Create);      //创建设置文件
                        BinaryWriter bw = new BinaryWriter(fis);                                        //创建数据流
                        bw.Write(chnCount);                                                             //写入通道数量
                        foreach (int i in _nodesData.GetAllFloatData().Keys)                           //保存.dat文件
                        {
                            bw.Write(i);                                                                //写入测点号（节点编号）
                            bw.Write(i);                                                                //写入节点编号
                            bw.Write(131072);//??                                                       //写入采样方式
                            bw.Write(_nodesData.GetAllNodeAcq()[i].Frequency);                          //写入采样频率
                            bw.Write(minlength); //todo                                                 //写入采样长度
                            bw.Write(1);                                                                //写入未知参数
                            bw.Write((char)0);                                                          //写入测点信息
                            bw.Write("V"); //todo:改为_config里的单位                                   //写入工程单位
                            bw.Write("2011/11/11/11:11:11");                                            //写入日期
                            bw.Write(1.0f);                                                             //写入前端放大倍数
                            bw.Write(1.0f);                                                             //写入参数K
                            bw.Write((float)0);                                                         //写入参数B
                            bw.Write(0.0f);                                                             //写入抗混叠滤波
                        }
                        bw.Flush();                                                                     //将所有数据写入文件
                        bw.Close();                                                                     //关闭数据流
                        fis.Close();                                                                    //关闭文件
                        //保存.dat文件
                        fis = new FileStream(saveFileDialog.FileName.Replace(".set", ".dat"), FileMode.Create);     //创建数据文件
                        bw = new BinaryWriter(fis);                                                                 //创建数据流
                        foreach (int id in _nodesData.GetAllFloatData().Keys)                                       //保存.dat文件
                        {
                            for (int j = 0; j < minlength; j++)
                            {
                                bw.Write(_nodesData.GetAllFloatData()[id][j]);                                      //保存每一个数据
                            }
                        }
                        bw.Flush();                                                                                 //将所有数据写入文件
                        bw.Close();                                                                                 //关闭数据流
                        fis.Close();                                                                                //关闭文件
                        MessageBox.Show("转换完成！");
                        break;
                    default:
                        MessageBox.Show("文件后缀有误！");
                        break;
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show("错误：" + ex.Message);
            }
        }

        private void tsb_databack_Click(object sender, EventArgs e)
        {
            if (!_dataListener.SerialPortIsOpen())
            {
                MessageBox.Show("串口没有打开 !");
                return;
            }
            Form_DataBack frmDataBack = new Form_DataBack(nodesTopology1.GetAllEndNode());
            frmDataBack.DataBackCmdEvent += FrmDataBack_DataBackCmdEvent;
            frmDataBack.ShowDialog();
            frmDataBack.Dispose();
        }

        private void FrmDataBack_DataBackCmdEvent(DataBackStructure dbStruc)
        {
            List<byte> lb = new List<byte>();
            lb.AddRange(_structBytes.StructToBytes(dbStruc, Marshal.SizeOf(dbStruc)));
            lb.Add((byte)nodesTopology1.GetNextNodeOfGetway(dbStruc.NodeID));// 网关到本节点的下一跳地址，网络参数传递时用，为0发送给所有节点
            lb.Insert(0, (byte)CmdType.TransferCmd);
            lb.Insert(0, (byte)SerialPackType.CmdPack);
            SendSerialPack(lb);
            _nodesData.ClearAllNodeData();                                  //清除所有节点数据
            _isLive = true;
        }

        private void tsb_canceldataback_Click(object sender, EventArgs e)
        {
            if (!_dataListener.SerialPortIsOpen())
            {
                MessageBox.Show("串口没有打开 !");
                return;
            }
            List<byte> lb = new List<byte>();
            DataBackStructure ast = new DataBackStructure();
            ast.TransferMode = TransferMode.Stop;
            lb.AddRange(_structBytes.StructToBytes(ast, Marshal.SizeOf(ast)));
            lb.Add((byte)0); // 网关到本节点的下一跳地址，网络参数传递时用，为0发送给所有节点
            lb.Insert(0, (byte)CmdType.TransferCmd);
            lb.Insert(0, (byte)SerialPackType.CmdPack);
            SendSerialPack(lb);
        }

        private void tsb_stop_Click(object sender, EventArgs e)
        {
            List<byte> lb = new List<byte>();
            AcqStructure ast = new AcqStructure();
            ast.AcqMode = AcqMode.Stop;
            lb.AddRange(_structBytes.StructToBytes(ast, Marshal.SizeOf(ast)));
            lb.Add((byte)0); // 网关到本节点的下一跳地址，网络参数传递时用，为0发送给所有节点
            lb.Insert(0, (byte)CmdType.AcqCmd);
            lb.Insert(0, (byte)SerialPackType.CmdPack);
            SendSerialPack(lb);

            tsb_start.Enabled = false; //失能启动采集
            tsb_stop.Enabled = false;
        }

        #endregion

        #region 数据显示类型

        private void MenuItem_ShowU16_Click(object sender, EventArgs e)
        {
            if (MenuItem_ShowU16.Checked) return;
            MenuItem_ShowU16.Checked = true;
            MenuItem_Show16.Checked = false;
            MenuItem_Show24.Checked = false;
            _dataType = DataType.Unsigned16;
        }

        private void MenuItem_Show16_Click(object sender, EventArgs e)
        {
            if (MenuItem_Show16.Checked) return;
            MenuItem_ShowU16.Checked = false;
            MenuItem_Show16.Checked = true;
            MenuItem_Show24.Checked = false;
            _dataType = DataType.Signed16;
        }

        private void MenuItem_Show24_Click(object sender, EventArgs e)
        {
            if (MenuItem_Show24.Checked) return;
            MenuItem_ShowU16.Checked = false;
            MenuItem_Show16.Checked = false;
            MenuItem_Show24.Checked = true;
            _dataType = DataType.Signed24;
        }

        #endregion

        private void timer_test_Tick(object sender, EventArgs e)
        {
            List<float> lf = new List<float>();
            Random r = new Random();
            for (int i = 0; i < 10000; i++)
            {
                lf.Add(r.Next(100));
            }
            List<int> ld = _nodesData.GetShowNodes();
            foreach (CtlDataDrawer dd in ld.Select(i => _nodesData.GetDataDrawer(i)))
            {
                dd.AddaData(lf, true);
            }
        }

        //删除列表中节点
        private void tsMenuItem_deletenode_Click(object sender, EventArgs e)
        {

        }


        #region 菜单操作

        private void MenuItem_OpenFile_Click(object sender, EventArgs e)
        {
            tsb_openfile_Click(sender, e);
        }

        private void MenuItem_SaveFile_Click(object sender, EventArgs e)
        {
            tsb_savefile_Click(sender, e);
        }

        private void MenuItem_Exit_Click(object sender, EventArgs e)
        {
            Application.Exit();
        }

        private void MenuItem_ConnectWsn_Click(object sender, EventArgs e)
        {
            toolStrip_btn_config_Click(sender, e);
        }

        private void MenuItem_StartAcq_Click(object sender, EventArgs e)
        {
            tsb_start_Click(sender, e);
        }

        private void MenuItem_StopAcq_Click(object sender, EventArgs e)
        {
            tsb_stop_Click(sender, e);
        }

        private void MenuItem_DataBack_Click(object sender, EventArgs e)
        {
            tsb_databack_Click(sender, e);
        }

        private void MenuItem_DataBackCancel_Click(object sender, EventArgs e)
        {
            tsb_canceldataback_Click(sender, e);
        }

        private void MenuItem_NodeInfo_Click(object sender, EventArgs e)
        {
            toolStrip_btn_nodes_ifo_Click(sender, e);
        }

        private void MenuItem_SerialPortTool_Click(object sender, EventArgs e)
        {

        }

        private void MenuItem_about_Click(object sender, EventArgs e)
        {

        }

        private void MenuItem_AcqConfig_Click(object sender, EventArgs e)
        {
            toolStrip_btn_acqset_Click(sender, e);
        }

        #endregion

        private void clb_nodesshow_DragDrop(object sender, DragEventArgs e)
        {
            for (int i = 0; i < ((Array)e.Data.GetData(DataFormats.FileDrop)).Length; i++)
            {
                String path = ((Array)e.Data.GetData(DataFormats.FileDrop)).GetValue(i).ToString();
                OpenData(path);
            }
        }

        private void clb_nodesshow_DragEnter(object sender, DragEventArgs e)
        {
            e.Effect = e.Data.GetDataPresent(DataFormats.FileDrop) ? DragDropEffects.Link : DragDropEffects.None;
        }

        private void panel_data_DragDrop(object sender, DragEventArgs e)
        {
            clb_nodesshow_DragDrop(sender, e);
            string fname = ((System.Array)e.Data.GetData(DataFormats.FileDrop)).GetValue(0).ToString();
            System.IO.FileStream fs = new System.IO.FileStream(fname, System.IO.FileMode.Open, System.IO.FileAccess.Read);
            byte[] bytes = new byte[fs.Length];
            fs.Read(bytes, 0, (int)fs.Length);
            panel_data.Text = Encoding.Default.GetString(bytes);
        }

        private void panel_data_DragEnter(object sender, DragEventArgs e)
        {
            clb_nodesshow_DragEnter(sender, e);
            if (e.Data.GetDataPresent(DataFormats.FileDrop))
            {
                e.Effect = DragDropEffects.All;
            }
            else
            {
                e.Effect = DragDropEffects.None;
            }
        }

        private void MenuItem_black_Click(object sender, EventArgs e)
        {
            //ColorSet(1);
        }

        private void MenuItem_white_Click(object sender, EventArgs e)
        {
            //ColorSet(0);
        }

        private void MenuItem_Relevance_Click(object sender, EventArgs e)
        {
            
        }

        private void MenuItem_DataClear_Click(object sender, EventArgs e)
        {
            _nodesData.ClearAllNodeData();
        }
    }
}